#include "cx_format.h"

static float cx_format_StringToFloat(const char* str);
static int cx_format_DecStringToInt(const char *str);
static unsigned int cx_format_DecStringToUint(const char* str);
static unsigned int cx_format_HexStringToInt(const char *str);
static int cx_format_IntToDecString(int value, char *dst);
static int cx_format_IntToHexString(unsigned int value, char *dst);
static int cx_format_FloatToString(float value, char *dst, int precision);

cx_format_interface_t cx_format =
{
    ._DecStringToInt  = cx_format_DecStringToInt,
    ._DecStringToUint = cx_format_DecStringToUint,
    ._FloatToString   = cx_format_FloatToString,
    ._HexStringToUint  = cx_format_HexStringToInt,
    ._IntToDecString  = cx_format_IntToDecString,
    ._IntToHexString  = cx_format_IntToHexString,
    ._StringToFloat   = cx_format_StringToFloat,
};

static char cx_char_tolower(char ch)
{
    char ret = ch;
    if(ch >= 65 && ch <= 90)
    {
        ret = ch + 32;
    }
    return ret;
}

static float cx_format_StringToFloat(const char* str)
{
    float ret = 0,f_tmp = 0;
    int i_tmp=0,num = 0, i=0, positive_flag = 0;;

    if(*str == '-')
    {
        positive_flag = 1;
        ++str;
    }
    for(; str[i] != '.' && str[i] != '\0'; i++)
    {
        ++num;
    }
    // printf("integer num:%d,\n", num);
    for(int j=0; j<num; j++)
    {
        i_tmp *= 10;
        i_tmp += str[j] - '0';
    }
    // printf("integer part:%d,\n", i_tmp);
    str += i;
    if(*str == '\0')
    {
        f_tmp = 0;
    }
    else
    {
        ++str;
        for(i = 0, num = 0; str[i]!= '\0'; i++)
        {
            ++num;
        }
        for(; num>0; --num)
        {
            f_tmp += str[num-1] - '0';
            f_tmp /= 10;
        }
    }
    // printf("float part:%f,\n", f_tmp);
    ret = i_tmp + f_tmp;
    return (positive_flag)?(0-ret):(ret);
}

static unsigned int cx_format_DecStringToUint(const char* str)
{
    unsigned int ret = 0;
    int num = 0, i=0;
    for(; str[i]!= '\0'; i++)
    {
        ret *= 10;
        ret += str[i] - '0';
    }
    return ret;
}
static int cx_format_DecStringToInt(const char *str)
{
    int ret = 0;
    int positive_flag = 0;
    if(*str == '-')
    {
        positive_flag = 1;
        ++str;
    }
    ret = cx_format_DecStringToUint(str);
    ret = positive_flag?(0-ret):ret;
    return ret;
}

static unsigned int cx_format_HexStringToInt(const char *str)
{
    int ret = 0;
    int num = 0, i=0, positive_flag = 0;
    char ch;
    if(str[0] == '0' && ((str[1] == 'x') || (str[1] == 'X')))
    {
        str += 2;
    }
    for(; str[i]!= '\0'; i++)
    {
        if(str[i] >= '0' && str[i] <= '9')
        {
            num = str[i] - '0';
        }
        else if((ch = cx_char_tolower(str[i])) >= 'a' && ch <= 'f')
        {
            
            num = ch - 'a' + 10;
        }
        else
            break;
        
        ret <<= 4;ret |= num;
    }
    return ret;
}

static int  cx_format_IntToDecString(int value, char *dst)
{
    int i = 0;
    int num = 0, ret = 0;
    char swap_ch;

    if(value < 0)
    {
        *dst = '-';
        ++dst,ret = 1;
        value = 0-value;
    }
    else if(value == 0)
    {
        *dst = '0';
        num++;
    }
    while(value)
    {
        dst[i++] = (value % 10) + '0';
        value /= 10;
        ++num;
    }
    for(int j = 0; j+j <= num-1; j++)
    {
        swap_ch = dst[j];
        dst[j] = dst[num-1-j];
        dst[num-1-j] = swap_ch;
    }
    dst[i] = '\0';
    return ret+num;
}

static int cx_format_IntToHexString(unsigned int value, char *dst)
{
    int i = 0;
    int num = 0, ret = 0;
    char swap_ch;

    // if(value < 0)
    // {
    //     *dst = '-';
    //     ++dst, ++num;
    //     value = 0-value;
    // }

    while(value)
    {
        dst[i++] = ((value & 0x0000000f) > 9)?(value & 0x0000000f) + 'a' - 10: (value & 0x0000000f) + '0';
        value >>= 4;
        ++num;
    }
    for(int j = 0; j+j <= num-1; j++)
    {
        swap_ch = dst[j];
        dst[j] = dst[num-1-j];
        dst[num-1-j] = swap_ch;
    }
    dst[i] = '\0';
    return ret+num;
}

static int cx_format_FloatToString(float value, char *dst, int precision)
{
    int i = 0;
    int num = 0, tmp, float_num;

    if(value < 0)
    {
        *dst = '-';
        ++dst, ++num;
        value = 0-value;
    }

    tmp = value;
    tmp = cx_format_IntToDecString(tmp, dst);
    if(tmp == 0)
    {
        *(dst++) = '0';
    }

    dst += tmp;
    *(dst++) = '.';
    value -= (int)value;
    float_num = precision - tmp;
    for(i = 0; i<float_num; i++)
    {
        value *= 10;
    }

    tmp = value;
    tmp = cx_format_IntToDecString(tmp, dst);
    dst += tmp;
    tmp = float_num - tmp;
    for(int i= 1; i<float_num - tmp + 1; i++)
    {
        *(dst+tmp-i) = *(dst - i);
    }
    float_num = float_num - tmp;
    for(int i= 0; i<tmp; i++)
    {
        *(dst - float_num + i) = '0';
    }
    return precision + num + 1;
}